package cn.mjnxin.iot.connector.coder;

import java.net.InetSocketAddress;
import java.util.List;

import cn.mjnxin.iot.base.constant.ConstantValue;
import cn.mjnxin.iot.base.domain.ChannelData;
import cn.mjnxin.iot.base.log.LogWorker;
import cn.mjnxin.iot.base.util.CommonUtil;
import cn.mjnxin.iot.connector.context.ConnectorContext;
import cn.mjnxin.iot.connector.context.IPeerContext;
import cn.mjnxin.iot.transfer.TransferExchange;
import cn.mjnxin.iot.transfer.TransferExchange.IUnpacker;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

/**
 * 解码器，将字节形式的报文解码成ChannelData对象
 * 
 * 如果当前拦截器没有向out中写入数据则后续的handler也不会被执行了

 * @author CLG 2023年10月10日
 * @version V1.0.0
 */
public class Gate2HostDecoder extends ByteToMessageDecoder implements IUnpacker{
	/**
	 * 匹配所有协议
	 */
	private final boolean      isAllMatch;
	private final Integer      pid;
	// 日志等级 0：无日志 1：报文长度日志 2：报文内容日志 3：所有日志
	private int   logLevel = 0;
    private final IPeerContext context;
    
    public Gate2HostDecoder(boolean isAllMatch, Integer pid, int logLevel, IPeerContext context) {
    	this.isAllMatch = isAllMatch;
    	this.pid = pid;
    	this.logLevel = logLevel;
        this.context = context;
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
    	TransferExchange.decode(ctx, in, out, this, logLevel);
    }

    public ChannelData unpackOnePackage(Channel channel, ChannelData originData, int type, boolean isIPV4) {
        InetSocketAddress insocket = (InetSocketAddress)channel.remoteAddress();
        String ipAddress = CommonUtil.getIpAddress(insocket);
        originData.setGateAddress(ipAddress);
        if (!isAllMatch && originData.getPid() != pid.intValue()) {
        	LogWorker.error(String.format("!isAllMatch && originData.pid: %d != pid: %d", originData.getPid(), pid));
        	return null;
        }
        
        boolean notTransfer = originData.getType() != ConstantValue.TYPE_TERMINAL_TO_HOST;
        if (notTransfer) { // 网关和前置内部交互报文不转发
            if (originData.getType() == ConstantValue.TYPE_GATE_LOGIN_HOST) {
            	if (logLevel > 0)
            	LogWorker.logForce(String.format("Gate %s 登录%s", originData.getGateAddress(), ConnectorContext.CONNECTOR_NAME));
            }
            else if (originData.getType() == ConstantValue.TYPE_TERMINAL_LINK) {
            	if (logLevel > 0)
            	LogWorker.logForce(String.format("%s：%s 连接", ConnectorContext.PEER_NAME, originData.getTerminalAddress()));
                context.addPeer(originData.getTerminalAddress(), originData.getPid(), originData.getGateAddress()); // 增加
            }
            else if (originData.getType() == ConstantValue.TYPE_TERMINAL_UNLINK) {
            	if (logLevel > 0)
            	LogWorker.logForce(String.format("%s：%s 断网断连", ConnectorContext.PEER_NAME, originData.getTerminalAddress()));
                context.removePeer(originData.getTerminalAddress()); // 断网断连
            }
            else if (originData.getType() == ConstantValue.TYPE_TERMINAL_CLOSED) {
            	if (logLevel > 0)
            	LogWorker.logForce(String.format("%s：%s 被%s断网断连", ConnectorContext.PEER_NAME, originData.getTerminalAddress(), ConnectorContext.CONNECTOR_NAME));
                context.closePeer(originData.getTerminalAddress()); // 断网断连
            }
            else if (originData.getType() == ConstantValue.TYPE_TERMINAL_TIMEOUT) {
            	if (logLevel > 0)
            	LogWorker.logForce(String.format("%s：%s 超时断连", ConnectorContext.PEER_NAME, originData.getTerminalAddress()));
                context.kickoutPeer(originData.getTerminalAddress()); // 超时断连
            }
            else {
            	LogWorker.logForce(String.format("其他未知包 originData type=%d", originData.getType()));
            }
            return null;
        }
        //多路负载均衡时，需要随时切换
        context.checkAndAddPeer(originData.getTerminalAddress(), originData.getPid(), originData.getGateAddress()); // 检测并设置对端标识
        return originData;
    }

	public boolean isAllMatch() {
		return isAllMatch;
	}

	public Integer getPid() {
		return pid;
	}

	public IPeerContext getContext() {
		return context;
	}
}
